#ifndef LIBSIM_ELEMENT_H_INCLUDED
#define LIBSIM_ELEMENT_H_INCLUDED

#include "libsim/utils/comparable.h"
#include "libsim/utils/uuid.h"
#include <forward_list>

namespace libsim {

class element
    : public comparable<element, element> {
public:
    virtual ~element()
    {
        if (parent_) {
            parent_->remove(this);
            parent_ = nullptr;
        }

        for (auto& child : children_) {
            delete child;
            child = nullptr;
        }
    }

    explicit element(element *parent = 0)
        : parent_(parent)
    {
        if (parent) {
            parent->add(this);
        }
    }

    element(const element &) = delete;
    element &operator=(const element &) = delete;

    element(element &&other) noexcept
    {
        swap(other);
    }

    element &operator=(element &&other) noexcept
    {
        swap(other);
        return *this;
    }

    void swap(element &other) noexcept
    {
        if (this != &other) {
            std::swap(uid_, other.uid_);
            std::swap(parent_, other.parent_);
            std::swap(children_, other.children_);
        }
    }

    auto id() const noexcept
    {
        return uid_;
    }

    const auto parent() const noexcept
    {
        return parent_;
    }

    auto parent() noexcept
    {
        return parent_;
    }

    const auto children() const noexcept
    {
        return children_;
    }

    auto children() noexcept
    {
        return children_;
    }

private:
    void add(element *child)
    {
        children_.push_front(child);
    }

    void remove(element *child)
    {
        children_.remove(child);
    }

    uuid uid_;
    element *parent_{nullptr};
    std::forward_list<element *> children_;
};

} // namespace libsim

#endif /* LIBSIM_ELEMENT_H_INCLUDED */
